Default scripts NB-IoT
- Overview
- S0
- Modbus
- M-Bus
- W M-Bus
Here you can find default NB-IoT LUA scripts for IoT Converter
-- Copyright 2021 ACRIOS Systems s.r.o.
-- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
-- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
function wordToBuffer(word)
-- little endian
local buff = ""
buff = buff .. string.char(word%256) .. string.char((word/256)%256) .. string.char(((word/256)/256)%256) .. string.char((((word/256)/256)/256)%256)
return buff
end
-- get and format S0 inputs
function getS0Data()
s01 = api.S0readCounter(1)
print("S0-1: "..tostring(s01))
s02 = api.S0readCounter(2)
print("S0-2: "..tostring(s02))
s03 = api.S0readCounter(3)
print("S0-3: "..tostring(s03))
s04 = api.S0readCounter(4)
print("S0-4: "..tostring(s04))
-- read old values
s01_l = api.getVar(16)
s02_l = api.getVar(17)
s03_l = api.getVar(18)
s04_l = api.getVar(19)
s01_ll = api.getVar(20)
s02_ll = api.getVar(21)
s03_ll = api.getVar(22)
s04_ll = api.getVar(23)
-- update old values
api.setVar(16, s01)
api.setVar(17, s02)
api.setVar(18, s03)
api.setVar(19, s04)
api.setVar(20, s01_l)
api.setVar(21, s02_l)
api.setVar(22, s03_l)
api.setVar(23, s04_l)
-- get battery voltage
v = api.getBatteryVoltage()
-- assemble the frame
buf = string.char(5) -- device class
buf = buf .. string.char(v%256) .. string.char((v/256)%256)
buf = buf .. wordToBuffer(s01) .. wordToBuffer(s01_l) .. wordToBuffer(s01_ll)
buf = buf .. wordToBuffer(s02) .. wordToBuffer(s02_l) .. wordToBuffer(s02_ll)
buf = buf .. wordToBuffer(s03) .. wordToBuffer(s03_l) .. wordToBuffer(s03_ll)
buf = buf .. wordToBuffer(s04) .. wordToBuffer(s04_l) .. wordToBuffer(s04_ll)
-- print the frame
print("Frame in hex: <devClass, voltage, S0_1, S0_1_last, ...>")
api.dumpArray(buf)
return buf
end
-- CONFIGURATION --
protocol = "UDP"
APN = "nb.m2mc"
PLMNID = "23003"
band = "20"
ip = "192.168.0.20"
port = 4242
receiveTimeout = 50
periodMinutes = 60
--
function onWake ()
print("onWake(), periodic wake up")
buf = getS0Data()
print("Sending to NB-IoT: " .. ip .. ":" .. tostring(port) .. " (" .. protocol .. ")")
res = api.nbSend(ip, port, buf, receiveTimeout, protocol)
if res == 0 then
print("Done, sent to NB-IoT")
else
print("Error " .. tostring(res) .. ", failed to send to NB-IoT!")
end
api.wakeUpIn(0,0,periodMinutes,0)
end
function onThreshold ()
print("onThreshold(), reason S0: " .. tostring(src))
buf = getS0Data()
print("Sending to NB-IoT: " .. ip .. ":" .. tostring(port) .. " (" .. protocol .. ")")
res = api.nbSend(ip, port, buf, receiveTimeout, protocol)
if res == 0 then
print("Done, sent to NB-IoT")
else
print("Error " .. tostring(res) .. ", failed to send to NB-IoT!")
end
end
function onStartup()
print("onStartup(), S0 persistent emulation...")
--set to threshold
api.S0setThreshold(1, 0)
api.S0setThreshold(2, 0)
api.S0setThreshold(3, 0)
api.S0setThreshold(4, 0)
s01 = api.getVar(20)
s02 = api.getVar(21)
s03 = api.getVar(22)
s04 = api.getVar(23)
api.S0initializeCounter(1, s01)
api.S0initializeCounter(2, s02)
api.S0initializeCounter(3, s03)
api.S0initializeCounter(4, s04)
api.nbAT("AT*MCGDEFCONT=\"IP\",\"" .. APN .."\"", 5000, 1)
api.nbAT("AT+COPS=1,2,\"".. PLMNID .."\"", 5000, 1)
api.nbAT("AT+CBAND=" .. band, 5000, 1)
end
-- Copyright 2021 ACRIOS Systems s.r.o.
-- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
-- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-----------------------
--- CONFIGURATION -----
-----------------------
----- NB-IoT ----------
APN = "nb.m2mc"
PLMNID = "23003"
protocol = "UDP" -- UDP or TCP
ip = "192.168.0.20"
port = 4242
receiveTimeout = 500 -- the maximum execution time in milliseconds
----- Modbus -----------
baudrate = 9600 -- baudrate: up to 921600 baud
parity = 0 -- communication parity: 0 for none, 1 for odd and 2 for even parity
stopBits = 1 -- number of stop bits: 1 or 2
dataBits = 8 -- number of data bits: 7 or 8
rxTimeout = 500 -- slave device receive timeout in ms
------ Timing ---------
-- device wakeup interval
periodHours = 2
periodMinutes = 30
-----------------------
-----------------------
-- CONFIGURATION END --
-----------------------
function onWake ()
-- set link parameters - e.g. 9600 baud, 8N1
api.rs485Setup(baudrate,parity,stopBits,dataBits)
api.rs485State(1)
-- EXAMPLE Modbus request:
-- check our applicaton notes or https://simplymodbus.ca/FC03.htm
-- req = ""
-- SLAVE ADDRESS (0xAA)| FUNCTION CODE (0x04)|
-- MSB REG ADDR (0x00) | LSB REG ADDR (0x08) |
-- MSB REG COUNT (0x00) | LSB REG COUNT (0x01)
-- req = pack.pack('<b6', 0xAA, 0x04, 0x00, 0x08, 0x00, 0x01)
-- crc = api.modbusCrc(req)
-- req = req .. crc -- add CRC, request is complete and ready for sending
if req == nil then
print("Please provide configuration!")
ans = "NO CONFIGURATION PROVIDED!"
else
print("To RS485: ")
api.dumpArray(req)
api.rs485Send(req)
ans,length=api.rs485Receive(rxTimeout)
print("From RS485: ")
api.dumpArray(ans)
api.delayms(500)
api.rs485State(0)
end
if #ans < 1 then
buf = "NO DATA RECEIVED"
else
buf = ans
end
print("To NBIOT: ")
api.dumpArray(buf)
print("Sending to NB-IoT")
api.nbSend(ip, port, buf, receiveTimeout, protocol)
print("Done sending")
print("Sleep now, wake in " .. tostring(periodHours) .. "hrs:" .. tostring(periodMinutes) .. "mins.....")
api.wakeUpIn(0,periodHours,periodMinutes,0)
end
function onStartup()
print("Starting up NB-IoT default Modbus script with APN settings")
result = api.nbAT("AT*MCGDEFCONT=\"IP\",\"" .. APN .."\"", 5000, 1)
print("APN result: " .. result)
result = api.nbAT("AT+COPS=1,2,\"" .. PLMNID .."\"", 5000, 1)
print("PLMNID result: " .. result)
end
-- Copyright 2021 ACRIOS Systems s.r.o.
-- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
-- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-----------------------
--- CONFIGURATION -----
-----------------------
----- NB-IoT ----------
APN = "nb.m2mc"
PLMNID = "23003"
protocol = "UDP" -- UDP or TCP
ip = "192.168.0.20"
port = 4242
receiveTimeout = 500 -- the maximum execution time in milliseconds
----- M-BUS -----------
baudrate = 2400 -- baudrate: up to 921600 baud
parity = 2 -- communication parity: 0 for none, 1 for odd and 2 for even parity
stopBits = 1 -- number of stop bits: 1 or 2
dataBits = 8 -- number of data bits: 7 or 8
------ Timing ---------
-- device wakeup interval
periodHours = 2
periodMinutes = 30
-----------------------
-----------------------
-- CONFIGURATION END --
-----------------------
function onWake ()
-- set link parameters - 2400 baud, 8E1
api.mbusSetup(baudrate,parity,stopBits,dataBits)
api.mbusState(1)
api.delayms(2000)
-- CREATE MBUS QUERY --
-- UD2
--b=pack.pack('<b5', 0x10, 0x5B, 0xFE, 0x59, 0x16)
b=pack.pack('<b5', 0x10, 0x7B, 0xFE, (0x7B+0xFE)%256, 0x16)
status,c,a,ci,ans = api.mbusTransaction(b,3000,1)
api.mbusState(0)
print("From MBus Calorimeter: ")
api.dumpArray(ans)
if #ans < 1 then
buf = "NO DATA RECEIVED"
else
buf = ans
end
print("To NBIOT: ")
api.dumpArray(buf)
print("Sending to NB-IoT")
api.nbSend(ip, port, buf, receiveTimeout, protocol)
print("Done sending")
print("Sleep now, wake in " .. tostring(periodHours) .. "hrs:" .. tostring(periodMinutes) .. "mins.....")
api.wakeUpIn(0,periodHours,periodMinutes,0)
end
function onStartup()
print("Starting up NB-IoT default script with APN settings")
result = api.nbAT("AT*MCGDEFCONT=\"IP\",\"" .. APN .."\"", 5000, 1)
print("APN result: " .. result)
result = api.nbAT("AT+COPS=1,2,\"" .. PLMNID .."\"", 5000, 1)
print("PLMNID result: " .. result)
end
-- Copyright 2021 ACRIOS Systems s.r.o.
-- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
-- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---- CONFIGURATION ----
APN = "nb.m2mc"
PLMNID = "23003"
periodDays = 1
periodHours = 0
periodMinutes = 0
proto = "UDP"
ip = "192.168.0.20"
port = 4242
---------------------
function processConfig(ret, cmd, cfg)
-- cmd 1 is selected for new filter configuration
if cmd == 1 then
print("New filter config:")
if cfg == nil or #cfg < 3 then
print("Purge filter, receive all")
api.wmbusFilter("purge", cfg)
filterLength = 0
api.setVar(1, filterLength)
else
api.dumpArray(cfg)
api.wmbusFilter("populate", cfg)
filterLength = #cfg/4
filterIdHasReceived = {}
for i=1, filterLength do
filterIdHasReceived[i] = 0
end
maxTimeout = filterLength*60000
api.setVar(1, filterLength)
end
end
-- cmd 2 is used to switch between WMBUS modes
if cmd == 2 then
if cfg == nil or cfg == '' then
print("Bad WMBUS mode, Specify C1 or T1 or S1")
else
print("New WMBUS mode: "..cfg)
api.wmbusSetup(10, "master", cfg, 1)
end
end
end
function onWake ()
filterLength = api.getVar(1)
print("Filter length: " .. tostring(filterLength))
if filterLength > 0 then
filterIdHasReceived = {}
for i=1, filterLength do
filterIdHasReceived[i] = 0
end
else
print("Error - no filter setup!")
ret, recved = api.nbSend(ip, port, string.char(255) .. 'NO FILTER, send ID filter to 1, mode to 2', 5000, proto)
if recved ~= nil then
if #recved > 1 then
processConfig(ret, string.byte(string.sub(recved,1,1)), string.sub(recved, 2))
end
end
end
start = api.getTick()
maxTimeout = filterLength*60000
-- receive WMBUS frames and upload to NBIOT in format [[meter filter ID] [raw wmbus frame]]
while filterLength > 0 do
while true do
-- if timeout, report not responding units
now = api.getTick()
if now - start > maxTimeout then
failing = ""
for i=1, filterLength do
failing = failing .. string.char(filterIdHasReceived[i])
end
print("List of failing Filter IDs:")
api.dumpArray(failing)
ret, recved = api.nbSend(ip, port, failing, 5000, proto)
if recved ~= nil then
if #recved > 1 then
processConfig(ret, string.byte(string.sub(recved,1,1)), string.sub(recved, 2))
end
end
print("Timeout receiving data from all meters...")
-- wake up later
api.wakeUpIn(periodDays, periodHours, periodMinutes, 0)
return
end
status, CI, manID, id, ver, devType, ctrlInfo, data, raw, filterId = api.wmbusReceiveFrame(60000, 1)
if raw ~= nil then
print("Received valid wMBUS frame...")
break
end
end
if filterId ~= nil then
if filterId > 0 then
if filterIdHasReceived[filterId] == 0 then
print("Upload data from node "..tostring(filterId).." to NBIOT.")
filterIdHasReceived[filterId] = 1
api.dumpArray(string.char(filterId) .. raw)
ret, recved = api.nbSend(ip, port, string.char(filterId) .. raw, 5000, proto)
if recved ~= nil then
if #recved > 1 then
processConfig(ret, string.byte(string.sub(recved,1,1)), string.sub(recved, 2))
end
end
else
print("Data from meter "..tostring(filterId).." already received.")
end
test = 1
for i=1, filterLength do
if filterIdHasReceived[i] == 0 then
test = 0
break
end
end
if test == 1 then
print("Received data from all meters, sleeping.......")
-- wake up later
api.wakeUpIn(periodDays, periodHours, periodMinutes, 0)
return
end
end
end
end
end
function onStartup()
print("Starting up WMBUS to NBIOT script, V1.2")
api.nbAT("AT*MCGDEFCONT=\"IP\",\"" .. APN .."\"", 5000, 1)
api.nbAT("AT+COPS=1,2,\"".. PLMNID .."\"", 5000, 1)
api.nbAT("AT+CBAND=20", 5000, 1)
-- Initial filter ids: 0x01673213, 0x19854733 ... (in little endian)
-- COMMENT OUT START
--filter = ""
--filter = filter .. string.char(0x13, 0x32, 0x67, 0x01) -- 0x01673213
--filter = filter .. string.char(0x33, 0x47, 0x85, 0x19) -- 0x19854733
--filterLength = #filter/4
--api.wmbusFilter("populate", filter)
-- COMMENT OUT END
ret, filterLength = api.wmbusFilter("fetch")
api.setVar(1, filterLength)
-- Start receiving at C1/T1 mode/frequency
api.wmbusSetup(10, "master","T1", 1)
end